package com.cellulam.framework.core;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.EnvironmentAware;
import org.springframework.core.env.AbstractEnvironment;
import org.springframework.core.env.EnumerablePropertySource;
import org.springframework.core.env.Environment;
import org.springframework.core.env.MutablePropertySources;
import org.springframework.stereotype.Component;

import java.util.Arrays;
import java.util.Properties;
import java.util.stream.StreamSupport;

/**
 *
 */
@Component
public class ProjectEnv implements EnvironmentAware {

    private static final Logger logger = LoggerFactory.getLogger(ProjectEnv.class);

    private Environment env;

    @Override
    public void setEnvironment(Environment environment) {
        this.env = environment;
    }

    /**
     * 根据 key, 查找 value, (带默认值)
     * @param prefix 前缀, 如果为空, 则忽略; 不为空, 则格式为<code>prefix</code>.
     * @param key 属性名
     * @param clazz 目标类型
     * @param defaultValue 默认值
     * @param <T> 返回值类型
     * @return value
     */
    public <T> T get(String prefix, String key, Class<T> clazz, T defaultValue) {
        String name = key;
        if (StringUtils.isNotEmpty(prefix)) {
            name = prefix + "." + key;
        }
        return env.getProperty(name, clazz, defaultValue);
    }

    /**
     * 根据 key, 查找 value, (无默认值)
     * @param prefix 前缀, 如果为空, 则忽略; 不为空, 则格式为<code>prefix</code>.
     * @param key 属性名
     * @param clazz 目标类型
     * @param <T> 返回值类型
     * @return value
     */
    public <T> T get(String prefix, String key, Class<T> clazz) {
        String name = key;
        if (StringUtils.isNotEmpty(prefix)) {
            name = prefix + "." + key;
        }
        return env.getProperty(name, clazz);
    }

    public String getString(String prefix, String key, String defaultValue) {
        return get(prefix, key, String.class, defaultValue);
    }

    public int getInt(String prefix, String key, int defaultValue) {
        return get(prefix, key, Integer.class, defaultValue);
    }

    public boolean getBoolean(String prefix, String key, boolean defaultValue) {
        return get(prefix, key, Boolean.class, defaultValue);
    }

    public String getString(String key, String defaultValue) {
        return get(null, key, String.class, defaultValue);
    }

    public int getInt(String key, int defaultValue) {
        return get(null, key, Integer.class, defaultValue);
    }

    public boolean getBoolean(String key, boolean defaultValue) {
        return get(null, key, Boolean.class, defaultValue);
    }


    public String getString(String key) {
        return get(null, key, String.class);
    }

    public int getInt(String key) {
        return get(null, key, Integer.class);
    }

    public boolean getBoolean(String key) {
        return get(null, key, Boolean.class);
    }

    public String resolve(String value) {
        if (org.springframework.util.StringUtils.hasText(value) && value.contains("$")) {
            return env.resolvePlaceholders(value);
        }
        return value;
    }

    public void printAllEnvProperties() {
        try {
            Properties props = new Properties();
            MutablePropertySources propSrcs = ((AbstractEnvironment) env).getPropertySources();
            logger.info("-------------------------- below is all env properties --------------------------");
            StreamSupport.stream(propSrcs.spliterator(), false)
                    .filter(ps -> ps instanceof EnumerablePropertySource)
                    .map(ps -> ((EnumerablePropertySource) ps).getPropertyNames())
                    .flatMap(Arrays::<String>stream)
                    .forEach(propName -> {
                        if (props.containsKey(propName)) {
//                            System.out.println("\t env duplicate key#" + propName + ", value is " + props.getProperty(propName));
                            logger.info("\t env duplicate key# {}, value is {}", propName, props.getProperty(propName));
                        }
                        props.setProperty(propName, env.getProperty(propName));

                    });
            props.stringPropertyNames().forEach(p -> logger.info("{} = {}", p, props.get(p)));
        } catch (Exception e) {
            logger.error("print all env-props error", e);
        }
    }

}
